﻿///////////////////////////////////////////////////////////////////////////////
//
// This file is part of the BassDrop project
//   https://code.google.com/p/bass-drop/
//
//
// Creator:	Gergely Krajcsovszki (krajcsovszkig@hotmail.com)
// Date:	2013-09-28 18:00
//
//
// Copyright © 2013-2014. Gergely Krajcsovszki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using BassDrop.Core.Common.Data.IO.Portable;

namespace BassDrop.Plugins.NAudioDecoder.Localization
{
	/// <summary>
	/// Class representing a language for the system
	/// </summary>
	public class PluginLanguage
	{
		#region Static properties

		/// <summary>
		/// List of available languages
		/// </summary>
		private static readonly Dictionary<string, PluginLanguage> s_AvailableLanguages = new Dictionary<string, PluginLanguage>();

		/// <summary>
		/// The extension of language files with a leading dot
		/// </summary>
		private static readonly string s_LanguageFileExtension = ".xml";

		/// <summary>
		/// Readonly list of available languages
		/// </summary>
		public static IEnumerable<PluginLanguage> AvailableLanguages
		{
			get
			{
				return s_AvailableLanguages.Values.AsEnumerable();
			}
		}

		/// <summary>
		/// The default, inbuilt language
		/// </summary>
		private static readonly PluginLanguage DefaultLanguage = new PluginLanguage()
		{
			LanguageFilePath = null,
			LanguageCode = "en",
			Name = "English (embedded)"
		};

		#endregion Static readonly fields

		#region Instance properties

		/// <summary>
		/// The localized name of this language
		/// </summary>
		public string Name
		{
			get;
			private set;
		}

		/// <summary>
		/// Path to the file containing the localizations for this language
		/// </summary>
		public Uri LanguageFilePath
		{
			get;
			private set;
		}

		/// <summary>
		/// The 2 letter name of the language represented by this object
		/// </summary>
		public string LanguageCode
		{
			get;
			private set;
		}

		#endregion Instance properties

		/// <summary>
		/// Returns the name of the supported language closest to the passed one.
		/// If the passed name is not recognized/supported, "en" is returned.
		/// </summary>
		/// <param name="language">the 2 letter name of the preferred language</param>
		/// <returns></returns>
		public static string GetClosestSupportedLanguage( string language )
		{
			if ( String.IsNullOrEmpty( language ) )
			{
				return "en";
			}

			language = language.ToLower();

			if ( s_AvailableLanguages.ContainsKey( language ) )
			{
				return language;
			}

			return "en";
		}

		/// <summary>
		/// Returns the language object for the closest supported language of the passed one.
		/// </summary>
		/// <param name="language">the 2 letter name of the preferred language</param>
		/// <returns></returns>
		public static PluginLanguage ForLanguage( string language )
		{
			language = GetClosestSupportedLanguage( language );

			if ( s_AvailableLanguages.ContainsKey( language ) )
			{
				return s_AvailableLanguages[language];
			}
			else
			{
				return DefaultLanguage;
			}
		}

		/// <summary>
		/// Adds the language to the list of available languages
		/// </summary>
		/// <param name="language"></param>
		public static void AddLanguage( PluginLanguage language )
		{
			s_AvailableLanguages.Add( language.LanguageCode.ToLower(), language );
		}

		/// <summary>
		/// Parses a language object out of a file on the passed path
		/// </summary>
		/// <param name="filePath"></param>
		/// <param name="fileHandler">the file handler for the application</param>
		/// <returns></returns>
		public static PluginLanguage FromFile( Uri filePath, IFileHandler fileHandler )
		{
			using ( var stream = fileHandler.GetStream( filePath.LocalPath, PortableFileMode.Open, PortableFileAccess.Read, PortableFileShare.Read ) )
			{
				XDocument doc = XDocument.Load( stream );

				return new PluginLanguage()
				{
					LanguageFilePath = filePath,
					Name = doc.Root.Attribute( "Name" ).Value,
					LanguageCode = doc.Root.Attribute( "LanguageCode" ).Value
				};
			}
		}

		/// <summary>
		/// Scrapes a directory for language files and adds all of them to the list of available languages
		/// </summary>
		/// <param name="directoryPath"></param>
		/// <param name="fileHandler"></param>
		public static void ScrapeLanguagesFrom( string directoryPath, IFileHandler fileHandler )
		{
			foreach ( var item in fileHandler.GetFiles( directoryPath ).Where( ( file ) => file.EndsWith( s_LanguageFileExtension ) ) )
			{
				try
				{
					AddLanguage( PluginLanguage.FromFile( new Uri( item ), fileHandler ) );
				}
				catch ( Exception e )
				{
					// don't bother with faulty files unless debugging
					System.Diagnostics.Debug.Assert( false, "Failed to load language file because\r\n" + e.ToString() );
				}
			}
		}
	}
}
